﻿using System.Diagnostics;
using System.IO;
using System.Net;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Net.Http.Json;
using System.Text;
using System.Windows;
using Microsoft.Win32;
using SMCL.Core.Utils.Auth.Json;
using SMCL.Core.Utils.Static;

namespace SMCL.Core.Utils.Auth
{
    internal class Auth
    {
        public static async Task<AuthResult?> RunAuth()
        {
            try
            {
                //step 0：准备工作
                Token token;
                var client = new HttpClient();
                client.DefaultRequestHeaders.UserAgent.Add(new(Launcher.Brand, System.Reflection.Assembly.GetExecutingAssembly().GetName().Version?.ToString()));
                client.DefaultRequestHeaders.UserAgent.Add(new("Microsoft.NET", Environment.Version.ToString()));
                client.DefaultRequestHeaders.Accept.Add(new("application/json"));
                if (!File.Exists("RefreshToken.txt"))
                {
                    //step 0.5：准备工作
                    using var listener = new HttpListener();
                    listener.Prefixes.Add("http://localhost:56125/");
                    string code = "";
                    listener.Start();
                    listener.BeginGetContext((result) =>
                    {
                        try
                        {
                            var context = listener.GetContext();
                            if (context.Request.QueryString["code"] != null)
                                code = context.Request.QueryString["code"];
                            HttpListenerResponse response = context.Response;
                            response.StatusCode = (int)HttpStatusCode.OK;
                            response.OutputStream.Write(Encoding.UTF8.GetBytes("<!DOCTYPE html>\r\n<html>\r\n<head>\r\n<meta charset=\"utf-8\">\r\n<title>验证完成</title>\r\n</head>\r\n<body>\r\n    <h1>验证完成。</h1>\r\n</body>\r\n</html>"));
                            response.Close();
                        }
                        catch (Exception ex)
                        {
                            MessageBox.Show($"验证失败：{ex.Message}");
                        }
                    }, null);
                    //step 1：开始验证
                    RegistryKey key = Registry.ClassesRoot.OpenSubKey(@"http\shell\open\command\");
                    string s = key.GetValue("").ToString();
                    MessageBox.Show("如果没有响应，请刷新看看");
                    Process.Start(s.Replace("%1", $"https://login.microsoftonline.com/consumers/oauth2/v2.0/authorize?client_id={DoNotShow.ClientId}&response_type=code&redirect_uri=http://localhost:56125&response_mode=query&scope=XboxLive.signin offline_access"));
                    while (string.IsNullOrEmpty(code))
                        await Task.Delay(100);
                    //step 2：获取授权令牌
                    var content = new StringContent($"client_id={DoNotShow.ClientId}&code={code}&grant_type=authorization_code&redirect_uri=http://localhost:56125&scope=XboxLive.signin offline_access", new MediaTypeHeaderValue("application/x-www-form-urlencoded"));
                    var response = await client.PostAsync("https://login.microsoftonline.com/consumers/oauth2/v2.0/token", content);
                    token = await response.Content.ReadFromJsonAsync<Token>();
                    File.WriteAllText("RefreshToken.txt", token.RefreshToken);
                }
                else
                {
                    //step 2：获取授权令牌
                    var content = new StringContent($"client_id={DoNotShow.ClientId}&refresh_token={File.ReadAllText("RefreshToken.txt")}&grant_type=refresh_token&scope=XboxLive.signin offline_access", new MediaTypeHeaderValue("application/x-www-form-urlencoded"));
                    var response = await client.PostAsync("https://login.microsoftonline.com/consumers/oauth2/v2.0/token", content);
                    token = await response.Content.ReadFromJsonAsync<Token>();
                }
                //step 3：XBox Live 身份验证
                var content1 = JsonContent.Create(new UserAuthenticateRequest()
                {
                    Properties = new()
                    {
                        AuthMethod = "RPS",
                        SiteName = "user.auth.xboxlive.com",
                        RpsTicket = token.AccessToken.StartsWith("d=") ? token.AccessToken : "d=" + token.AccessToken,
                    },
                    RelyingParty = "http://auth.xboxlive.com",
                    TokenType = "JWT"
                });
                var response1 = await client.PostAsync("https://user.auth.xboxlive.com/user/authenticate", content1);
                var userAuthenticateResponse = await response1.Content.ReadFromJsonAsync<UserAuthenticateResponse>();
                //step 4：XSTS 身份验证
                var content2 = JsonContent.Create(new XstsAuthenticateRequest()
                {
                    Properties = new()
                    {
                        SandboxId = "RETAIL",
                        UserTokens = [userAuthenticateResponse.Token],
                    },
                    RelyingParty = "rp://api.minecraftservices.com/",
                    TokenType = "JWT"
                });
                var response2 = await client.PostAsync("https://xsts.auth.xboxlive.com/xsts/authorize", content2);
                var xstsAuthenticateResponse = await response2.Content.ReadFromJsonAsync<XstsAuthenticateResponse>();
                //step 5：获得 Minecraft 访问令牌
                //懒得打类型声明了，手写JSON吧
                var content3 = new StringContent($"{{\"identityToken\": \"XBL3.0 x={xstsAuthenticateResponse.DisplayClaims.Xui[0].UserHash};{xstsAuthenticateResponse.Token}\"}}", new MediaTypeHeaderValue("application/json"));
                var response3 = await client.PostAsync("https://api.minecraftservices.com/authentication/login_with_xbox", content3);
                var minecraftAuthenticateResponse = await response3.Content.ReadFromJsonAsync<MinecraftAuthResponse>();
                //step 5.5：加请求头
                client.DefaultRequestHeaders.Authorization = new("Bearer", minecraftAuthenticateResponse.AccessToken);
                //step 6：检查游戏拥有情况
                var response4 = await client.GetAsync("https://api.minecraftservices.com/entitlements/mcstore");
                var mcStoreResponse = await response4.Content.ReadFromJsonAsync<McStoreResponse>();
                if (Array.Find(mcStoreResponse.Items, (sth) => sth.Name == "game_minecraft" || sth.Name == "product_minecraft") is null)
                {
                    MessageBox.Show("你似乎没有购买游戏！如果你要以另一个账号登陆，请删除RefreshToken.txt（如果有的话）");
                    return null;
                }
                //step 7：获取玩家 UUID
                var response5 = await client.GetAsync("https://api.minecraftservices.com/minecraft/profile");
                var mcProfileResponse = await response5.Content.ReadFromJsonAsync<McProfileResponse>();
                return new()
                {
                    Name = mcProfileResponse.Name,
                    Token = minecraftAuthenticateResponse.AccessToken,
                    Uuid = mcProfileResponse.Id
                };
            }
            catch (Exception ex)
            {
                MessageBox.Show($"验证失败：{ex.Message}");
                return null;
            }
        }
    }
}
